For a simple ScriptX title that is to be distributed to others, you might define a single module that uses the ScriptX module. It can also use other modules-such as modules associated with library or accessory containers.
module MyOwnTitle uses ScriptX end
in module MyOwnTitle
-- build your title here . . .
For simple programs, encapsulating code within modules and importing and exporting variables is reasonably straightforward. Larger and more complex programs, with multiple modules that use and are used by each other, can create complex dependencies. In large networks of modules, it may become difficult to keep track of the relationships between modules.
The interface/implementation model is a model for designing networks of modules. Using the interface/implementation model, you can create modules with implicit circular use relationships. You can combine interfaces to construct customized, general interfaces that are based on the needs of the client module.
The interface/implementation model can also be used to define multiple interfaces to the same ScriptX program. For example, a code library could have an interface for end users and an interface for programmers-without duplicating any code
This section describes how the interface/implementation model can be used to create a better structure for large ScriptX programs.
in module
expression
and should have no code associated with them at all. Interface
modules are used by other modules, but do not use any other
modules.
module BakeryInterface
exports rye
end
Bakery
, uses the
BakeryInterface
module and provides a definition
for the imported variable rye
.
Bakery
is the implementation module for
BakeryInterface
.module Bakery
uses BakeryInterface
end
in module Bakery
global rye := "rye bread"
Bakery
module does not, and should not,
re-export the rye
variable. The purpose of the
Bakery
module is simply to provide an
implementation for variables exported elsewhere; it is not
used by any other modules.
Now, any modules that use BakeryInterface
(clients of the BakeryInterface
module)
automatically receive the definitions of those variables from
Bakery
even though they were not explicitly
exported. For example, if the Delicatessen
module
uses BakeryInterface
, Delicatessen
has access to the definition of rye
in
Bakery
even though Bakery
didn't
export rye
and Delicatessen
didn't
use Bakery
.
module Delicatessen
uses ScriptX, BakeryInterface
end
in module Delicatessen
print rye
"rye bread"
Delicatessen
needs to use the
ScriptX module to have access to the print
function. Like other global functions, print
is a
part of the object system, and not of the ScriptX language
itself.Although using modules in this way may seem like an unnecessary level of indirection, it allows you to organize and combine interface modules freely without worrying about where the contents of those interface modules are defined.
Figure 9-6 actually depicts the
relationship between the three "system modules" that are
defined by ScriptX: the ScriptX
,
Substrate
, and Scratch
modules. In
Figure 9-7, the diagram in Figure 9-6 has been relabeled to
demonstrate this relationship between system modules. The
ScriptX
modules acts as an interface module, and
the Substrate
module as an implementation module.
The Scratch
module, and any user-defined modules
that use the ScriptX
module, are clients of the
ScriptX
module.
Here is an example of a small set of modules, for draw and paint operations. The implementation for each group of operations requires the use of the other, a circular reference. Using the interface/implementation model, the circularity is broken as all the interface modules are defined before any module tries to use any other module.
module DrawInterface
exports line, rectangle, circle
end
module PaintInterface
exports pencil, brush, fill
end
module DrawImplementor
uses ScriptX, DrawInterface, PaintInterface
end
module PaintImplementor
uses ScriptX, PaintInterface, DrawInterface
end
If you were to draw the relationships between these modules, they might look like this:
DrawImplementor
module provides
definitions for the DrawInterface
module. It is
also a client of the PaintInterface
module, whose
definitions are, in turn, provided in
PaintImplementor
. Finally,
PaintImplementor
is a client of
DrawInterface
, which completes the
circularity.For example, say you had two ScriptX programs, one for drawing functions (vector graphics) and one for painting (bitmap graphics). Using the interface-implementation module for organizing modules, you would create four modules: two interfaces and two implementors:
GraphicsInterface
) that does nothing except use
the other two interface modules, and re-export the variables
it imported from those modules. Clients of
GraphicsInterface
have access to all the
variables in both the PaintInterface
and
DrawInterface
modules
Suppose you have created a large body of ScriptX code for
producing various musical sounds. For that single large
MusicModule
implementation, you could have
multiple interfaces, each of which provides access to only
some of the variables within that module. For example, a
ClassicalMusic
interface module would provide
access to violin
, flute
, and
harpsichord
; a RockNRoll
module
would include electricGuitar
and
drumKit
; and a Madrigals
module
would include access to voices such as altoVoice
,
and bassVoice
.
NewUser
, IntermediateUser
,
or AdvancedUser
. By providing separate interfaces
for each of those users, you could provide a subset of
features to the new user, more features to the intermediate
user, and a complete set to the advanced user.The pass-through model is a variation on the standard interface/implementation model, useful for defining several discrete protocols and combining them into a single interface.
The build module contains the code that builds the title. Often, it is a special module that corresponds with the build file for a project. The build file is compiled in the build module. By avoiding references from other modules to any variable that is defined in the build module, you can keep the code that is used to build the project from being loaded at runtime. A build module is often a transient object-an object that is not saved to the object store. The build module is the best place for variables that represent compilation status, since those variables should mean nothing at runtime.
A ScriptX title can be a constructive experience, one where users add new objects to create what is, in effect, their own title. In a sense, publishing a title that is a constructive experience means publishing a protocol.
Of course, two programs cannot interact without knowing something about each other. A title's accessory protocol is, in effect, a list of names that are recognizable to both the title and to accessories. These names represent classes, objects, functions, and generics that are public in any module that uses the accessory protocol. Although it is not necessary to determine all possible interactions between objects in advance, a set of names must be agreed upon.
module GidgetAccessoryInterface
exports instance variables accessoryProtocols
exports addToPresenter, GidgetClass
end
The GidgetTitleImplementation
module, in turn,
uses both the ScriptX
and
GidgetAccessoryInterface
modules. Within this
module, the accessoryProtocols
instance variable,
the generic addToPresenter
, and the class
GidgetClass
are defined. Since they are defined
there, they are also saved there.
module GidgetTitleImplementation
uses ScriptX, GidgetAccessoryInterface
end
An accessory that uses the
GidgetAccessoryInterface
should define its own
module.
module GidgetAccessoryImplementation
uses ScriptX, GidgetAccessoryInterface
end
By now, it should be obvious that the accessory interface
model is a familiar one. Think of the ScriptX
module as the "accessory interface" for the ScriptX core
classes. Every module that uses the ScriptX
module is running as an accessory to ScriptX, which is
implemented in the Substrate
module. Just as the
substrate makes a portion of the names it defines visible in
the ScriptX
module, any user-defined module can
export some of the names it defines through its own interface
module.
This document is part of the ScriptX Language Guide, one of the volumes of the ScriptX Technical Reference Series. ScriptX is developed by the ScriptX Engineering Team at Apple Computer, successor to the Kaleida Engineering Team at Kaleida Labs, Inc.